let length = lazy (fun a -> Array.length (Lazy.force a))

let get = lazy (fun a i -> Lazy.force ((Lazy.force a).(Lazy.force i)))

let set = lazy (fun a i v -> (Lazy.force a).(Lazy.force i) <- v)

let make = lazy (fun n v -> Array.make (Lazy.force n) v)

let create = make

let init =
  lazy (fun n f -> Array.init (Lazy.force n)
	  (fun i -> lazy ((Lazy.force f) (lazy i))))

let make_matrix =
  let make_matrix_aux n m v =
    let n = Lazy.force n in
    let a = Array.make n (lazy [||]) in
      for i = 0 to pred n do
	a.(i) <- lazy (Array.create (Lazy.force m) v);
      done;
      a
  in
    lazy make_matrix_aux

let create_matrix = make_matrix

let append = lazy (fun a1 a2 -> Array.append (Lazy.force a1) (Lazy.force a2))

let concat =
  let concat_aux l = 
    let sz =
      (Lazy.force Lazy_list.fold_left)
	(lazy (fun acc a -> Array.length (Lazy.force a) + (Lazy.force acc)))
	(lazy 0) l
    in
      try
	let init =
	  ((Lazy.force Lazy_list.find)
	     (lazy (fun a -> Array.length (Lazy.force a) <> 0)) l).(0)
	in
	let res = Array.make sz init in
	let n = ref 0 in
	  (Lazy.force Lazy_list.iter)
	    (lazy (fun a ->
		     let a = Lazy.force a in
		     let l = Array.length a in
		     let k = !n in
		       for i = 0 to pred l do
			 res.(k+i) <- a.(i)
		       done;
		       n := k + l)) l;
	  res
      with Not_found -> [||]
  in
    lazy concat_aux

let sub =
  lazy (fun a s l -> Array.sub (Lazy.force a) (Lazy.force s) (Lazy.force l))

let copy = lazy (fun a -> Array.copy (Lazy.force a))

let fill =
  lazy (fun a o l v -> Array.fill (Lazy.force a) (Lazy.force o) (Lazy.force l)
	  v)

let blit =
  lazy (fun a1 o1 a2 o2 l -> Array.blit (Lazy.force a1) (Lazy.force o1)
	  (Lazy.force a2) (Lazy.force o2) (Lazy.force l))

let to_list =
  lazy (fun a ->
	  let a = Lazy.force a in
	  let len = Array.length a in
	  let rec f i =
	    if i = len then Lazy_list.LNil_
	    else Lazy_list.LCons_ (a.(i), lazy (f (i + 1)))
	  in
	    f 0)

let of_list =
  lazy (fun l ->
	  match Lazy.force l with
	    | Lazy_list.LNil_ -> [||]
	    | Lazy_list.LCons_ (hd, tl) ->
		let n = (Lazy.force Lazy_list.length) l in
		let a = Array.make n hd in
		let l = ref (Lazy.force tl) in
		for i = 1 to n - 1 do
		  match !l with
		    | Lazy_list.LNil_ -> assert false
		    | Lazy_list.LCons_ (hd, tl) ->
			l := Lazy.force tl;
			a.(i) <- hd;
		done;
		a)

let iter =
  lazy (fun f a -> Array.iter (fun x -> (Lazy.force f) x) (Lazy.force a))

let map =
  lazy (fun f a -> Array.map (fun x -> lazy ((Lazy.force f) x)) (Lazy.force a))

let iteri =
  lazy (fun f a -> Array.iteri (fun i x -> (Lazy.force f) (lazy i) x)
	  (Lazy.force a))

let mapi =
  lazy (fun f a -> Array.mapi (fun i x -> lazy ((Lazy.force f) (lazy i) x))
	  (Lazy.force a))

let fold_left =
  lazy (fun f v a -> Array.fold_left (fun acc v -> (Lazy.force f) (lazy acc) v)
	  (Lazy.force v) (Lazy.force a))

let fold_right =
  lazy (fun f a v -> Array.fold_right (fun v acc -> (Lazy.force f) v (lazy acc))
	  (Lazy.force a) (Lazy.force v))

let sort =
  lazy (fun cmp a -> Array.sort (fun v1 v2 -> (Lazy.force cmp) v1 v2)
	  (Lazy.force a))

let stable_sort =
  lazy (fun cmp a -> Array.stable_sort (fun v1 v2 -> (Lazy.force cmp) v1 v2)
	  (Lazy.force a))

let fast_sort =
  lazy (fun cmp a -> Array.fast_sort (fun v1 v2 -> (Lazy.force cmp) v1 v2)
	  (Lazy.force a))

let unsafe_get =
  lazy (fun a i -> Lazy.force (Array.unsafe_get (Lazy.force a) (Lazy.force i)))

let unsafe_set =
  lazy (fun a i v -> Array.unsafe_set (Lazy.force a) (Lazy.force i) v)
